﻿using Enterprises.Wpf.Core.Entity;
using Enterprises.Wpf.Core.Helper;
using Enterprises.Wpf.Core.Localization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace Enterprises.Wpf.Core.Modbus
{
    public class ModbusUdpServer : ModbusTcpServer
    {
        /// <summary>
        /// 获取或设置一次接收时的数据长度，默认2KB数据长度
        /// </summary>
        public int ReceiveCacheLength { get; set; } = 2048;


        /// <summary>
        /// 实例化一个ModbusUdp的服务器
        /// </summary>
        public ModbusUdpServer()
        {
        }

        /// <inheritdoc />
        public override void ServerStart(int port)
        {
            if (!base.IsStarted)
            {
                StartInitialization();
                CoreSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                CoreSocket.Bind(new IPEndPoint(IPAddress.Any, port));
                RefreshReceive();
                base.IsStarted = true;
                base.Port = port;
                base.LogNet?.Info(ToString(), StringResources.Language.NetEngineStart);
            }
        }

        /// <summary>
        /// 重新开始接收数据
        /// </summary>
        private void RefreshReceive()
        {
            AppSession appSession = new AppSession(CoreSocket);
            appSession.UdpEndPoint = new IPEndPoint(IPAddress.Any, 0);
            appSession.BytesBuffer = new byte[ReceiveCacheLength];
            CoreSocket.BeginReceiveFrom(appSession.BytesBuffer, 0, ReceiveCacheLength, SocketFlags.None, ref appSession.UdpEndPoint, AsyncCallback, appSession);
        }

        private void AsyncCallback(IAsyncResult ar)
        {
            if (!(ar.AsyncState is AppSession appSession))
            {
                return;
            }
            try
            {
                int num = appSession.WorkSocket.EndReceiveFrom(ar, ref appSession.UdpEndPoint);
                
                RefreshReceive();
                byte[] array = new byte[num];
                Array.Copy(appSession.BytesBuffer, 0, array, 0, num);
                OperateResult<byte[]> operateResult = ReadFromCoreServer(appSession, array);
                if (!operateResult.IsSuccess)
                {
                    RemoveClient(appSession, operateResult.Message);
                    return;
                }
                base.LogNet?.Debug(ToString(), "Udp " + StringResources.Language.Receive + "：" + array.ToHexString(' '));
                if (operateResult != null)
                {
                    appSession.WorkSocket.SendTo(operateResult.Content, operateResult.Content.Length, SocketFlags.None, appSession.UdpEndPoint);
                    base.LogNet?.Debug(ToString(), "Udp " + StringResources.Language.Send + "：" + operateResult.Content.ToHexString(' '));
                    RaiseDataReceived(appSession, array);
                }
                else
                {
                    RemoveClient(appSession);
                }
            }
            catch (ObjectDisposedException)
            {
            }
            catch (Exception ex2)
            {
                base.LogNet?.Error(ToString(), StringResources.Language.SocketEndReceiveException, ex2);
                RefreshReceive();
            }
            finally
            {
            }
        }

        /// <inheritdoc />
        public override string ToString()
        {
            return $"MelsecMcUdpServer[{base.Port}]";
        }
    }

}
